import copy
import hashlib
import os
import sys
import time
from datetime import datetime, timedelta
from typing import Any, Union, Tuple, List

import commentjson
import pytz
from blinker import NamedSignal
from flask.signals import Namespace


def eprint(*args, sep: str = ''):
    print(*args, sep, file=sys.stderr)


def time_str(sec, format: str = "%Y-%m-%d %H:%M:%S", zone: str = "Asia/Shanghai") -> str:
    tz = pytz.timezone(zone)
    dt_object = datetime.fromtimestamp(sec, tz)
    return dt_object.strftime(format)


def now_str(format: str = "%Y-%m-%d %H:%M:%S", zone: str = "Asia/Shanghai") -> str:
    return time_str(time.time(), format, zone)


def wait_quit():
    cmd: str = input("输入q退出:\n")
    while "q" != cmd:
        cmd = input("输入q退出:\n")


def wait_continue():
    cmd: str = input("输入c继续:\n")
    while "c" != cmd:
        cmd = input("输入c继续:\n")
    eprint("go to work...")


def add_list(l1: list, l2: list):
    if l2 and len(l2) > 0:
        for e in l2:
            l1.append(e)


def complete_url(url: str) -> str:
    if not url or len(url) == 0:
        return url
    if not url.startswith("https:"):
        if not url.startswith("//"):
            url = "//" + url
        url = "https:" + url
    return url


def mkdir(dir: str = None):
    if dir and len(dir) > 0:
        if not os.path.exists(dir):
            os.mkdir(dir)
            eprint(f"文件夹 {dir} 创建.")
        else:
            eprint(f"文件夹 {dir} 已存在.")


def get_str_arg(val, def_val: str) -> str:
    if val is None:
        return def_val
    v: str = str(val).strip()
    if len(v) == 0:
        return def_val
    return val


def load_json(json_file: str) -> Any:
    try:
        with open(file=json_file, mode='r', encoding='utf-8') as file:
            obj = commentjson.load(file)
            return obj
    except Exception as ex:
        raise ex


def dump_json(json_file: str, obj: Any) -> Any:
    try:
        with open(file=json_file, mode='w', encoding='utf-8') as file:
            file.write(commentjson.dumps(obj))
    except Exception as ex:
        raise ex


def md5(obj: Any) -> str:
    s = str(obj)
    hash_object = hashlib.md5(s.encode())
    return hash_object.hexdigest()


def pair_list_2_map(lt: list[Union[Tuple, List]]) -> dict:
    mp = {}
    if lt and len(lt):
        for t in lt:
            mp[t[0]] = mp[t[1]]
    return mp


def str_list_2_map(keys: list[str], values: list[str]) -> dict:
    mp = {}
    kl = len(keys)
    vl = len(values)
    if kl != vl:
        raise Exception(f"keys.len:{kl} != values.len:{vl}")
    for i in range(kl):
        mp[keys[i]] = values[i].strip().replace(' ', '')
    return mp


def fill_missing_dates(dates: list[str], fmt: str = '%Y-%m-%d'):
    """
    填充缺失日期
    :param dates:
    :param fmt:
    :return:
    """
    # 将字符串日期转换为 datetime 对象
    datetime_list = [datetime.strptime(date, fmt) for date in dates]
    # 生成起始日期和结束日期
    start_date = datetime_list[0]
    end_date = datetime_list[-1]
    # 生成日期序列
    date_range = [start_date + timedelta(days=i) for i in range((end_date - start_date).days + 1)]
    # 将日期序列转换回字符串格式
    date_range_str = [date.strftime(fmt) for date in date_range]
    # 找出缺失的日期
    missing_dates = [date for date in date_range_str if date not in dates]
    if missing_dates is None or len(missing_dates) == 0:
        return dates
    res = copy.copy(dates)
    # 插入缺失的日期到原始列表
    for i, date in enumerate(missing_dates):
        # 找到应该插入的位置
        index = date_range_str.index(date)
        res.insert(index, date)
    return res


def contains(s: str, l: list[str]) -> bool:
    for ss in l:
        if ss in s:
            return True
    return False


_provinces = [
    "北京市", "天津市", "河北省", "山西省", "辽宁省", "吉林省", "黑龙江省",
    "上海市", "江苏省", "浙江省", "安徽省", "福建省", "江西省", "山东省",
    "河南省", "湖北省", "湖南省", "广东省", "广西壮族自治区", "海南省",
    "重庆市", "四川省", "贵州省", "云南省", "西藏自治区", "陕西省",
    "甘肃省", "青海省", "宁夏回族自治区", "新疆维吾尔自治区", "内蒙古自治区",
    "香港特别行政区", "澳门特别行政区"
]


def fill_province(s: str) -> str:
    for p in _provinces:
        if s in p:
            return p
    return s


class FlaskSignal(Namespace):
    def __init__(self, id: str):
        super().__init__()
        self.id = id
        self.signal: NamedSignal = super().signal(id)
        self.signal.connect(self.receive)

    def receive(self, sender, data: str, **extra):
        raise Exception("子类实现")

    def send(self, sender, data: str, **extra):
        self.signal.send(sender, data=data, extra=extra)
